package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.constants.WemediaConstants;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import com.heima.wemedia.utils.WmThreadLocalUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper , WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmNewsService wmNewsService ;

    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //参数检查
        dto.checkParam();
        //分页查询
        /**
         * 有些字段在查询前还要进行参数检查  尚未完工
         */
        IPage page = new Page(dto.getPage() ,dto.getSize());
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        //状态，频道精确查询
        if (dto.getStatus() != null){
            queryWrapper.eq(WmNews::getStatus , dto.getStatus());
        }
        //频道精确查询
        if (dto.getChannelId() != null){
            queryWrapper.eq(WmNews::getChannelId , dto.getChannelId());
        }
        //发布时间范围查询
        if ((dto.getBeginPubDate()) != null && (dto.getEndPubDate() != null) ){
            queryWrapper.between(WmNews::getCreatedTime , dto.getBeginPubDate() , dto.getEndPubDate());
        }
        //关键字模糊查询
        if (dto.getKeyword() != null){
            queryWrapper.like(WmNews::getTitle , dto.getKeyword());
        }

        //根据当前作者查询
        queryWrapper.like(WmNews::getUserId , WmThreadLocalUtil.get().getId());
        //根据发布时间降序
        queryWrapper.orderByDesc(WmNews::getPublishTime);
        page = page(page, queryWrapper);

        PageResponseResult result = new PageResponseResult(dto.getPage() ,dto.getSize() , (int)page.getTotal()) ;
        result.ok(page.getRecords());
        return result;
    }

    @Autowired
    private WmNewsAutoScanService autoScanService ;

    @Autowired
    private WmNewsTaskService wmNewsTaskService ;

    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //0 参数校验
        if (dto == null || dto.getContent() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //1. 保存或修改文章
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto , wmNews);
        //其中有些参数无法拷贝如images，在dto中是结合，在wmnews中是str
        if ((dto.getImages() != null) && (dto.getImages().size() > 0 )){
            //[a.jpg,b.gpg] --> a.jpg,b.jpg
            String images = StringUtils.join(dto.getImages(), ",");
            wmNews.setImages(images);
        }
        //如果当前封面类型为自动前端传过来 -1 ，但是后端在存的时候存的是无符号tinint  所以如果是自动，暂时置空
        if (dto.getType() == WemediaConstants.WM_NEWS_TYPE_AUTO){
            wmNews.setType(null);
        }
        saveOrUploadNews(wmNews);

        //2. 判断是否为草稿 ，如果是草稿结束当前方法 而不是提交
        if (wmNews.getStatus() == WmNews.Status.NORMAL.getCode()){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //3 不是草稿，保存文章内容和素材之间的关系
        //抽取出前端传递过来的图片列表
        List<String> materials =  extractMaterials(wmNews);
        // 素材列表结合文章id保存到 WM_news_materials 表
        saveNewsMaterialRelations(wmNews , materials , WemediaConstants.WM_CONTENT_REFERENCE);
        //4 不是草稿，保存封面和素材之间的关系 如果封面的类型为自动，需要匹配封面图片
        saveRelationInfoForCover(dto , wmNews , materials);

        //文章自动审核
        autoScanService.autoScan(wmNews.getId().longValue());
        //以前是直接在这里审核文章，现在是创建一个任务，然后然让审核文章去消费这个任务
        //wmNewsTaskService.addNewsToTask(wmNews.getId(),wmNews.getPublishTime());


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 该方法用途
     * 第一个功能： 如果当前封面为类型为自动 ，设置 封面类型
     * 1 内容图片 > 1 , < 3 ,单图  ， 设置为type 1
     * 2 内容图片 >= 3 ,多图  ， 设置为type 3
     * 3 内容图片 无图,无图  ， 设置为type 0
     *
     * 功能二： 保存封面和素材的关联关系 到中间表
     *
     * @param dto 前端传过来的对象
     * @param wmNews 文章对象
     * @param materials 文章内容所涉的图片，不包含封面图片 --
     */
    private void saveRelationInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {

        List<String> images = dto.getImages();
        //判断封面类型是否为自动
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            //内容无图
            if (materials.isEmpty() || (materials.size() ==0) ){
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }else if ((materials.size() >= 1)  && (materials.size()<3 )   ){
                //内容少图
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                images = materials.stream().limit(1).collect(Collectors.toList());

            }else if(materials.size() >= 3){
                //内容多图
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                //截出来三个图
                images = materials.stream().limit(3).collect(Collectors.toList());
            }

            //上面确定了 文章封面的类型，开始更新一下文章
            if (!images.isEmpty() && images.size() > 0){
                wmNews.setImages(StringUtils.join(images , ","));
            }
            updateById(wmNews);
        }

        //第二个功能，保存封面和素材的关联关系
        if (!images.isEmpty() && images.size()>0){
            saveNewsMaterialRelations(wmNews , materials , WemediaConstants.WM_COVER_REFERENCE);
        }

    }

    /**
     * 处理文章内容如素材之间的关系 保存到中间表
     * @param wmNews
     * @param materials
     * @param type  0 内容和素材  1 封面和素材
     */
    @Autowired
    private WmMaterialMapper wmMaterialMapper ;

    private void saveNewsMaterialRelations(WmNews wmNews, List<String> materials , short type) {

        //判断前端传递集合是否为空
        if (materials != null && !materials.isEmpty()){

            //拿到图片ids 通过图片的url去查
            List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));
            //是否从数据库中查找到数据
            if (dbMaterials == null || dbMaterials.size() == 0){
                //抛出异常，异常可以使得数据库回滚
                throw  new CustomException(AppHttpCodeEnum.WEMEDIA_REFRIENCE_FAIL);
            }
            //是否查找到所有的资源 id  ,有些素材可能被删除了
            if (materials.size() != dbMaterials.size()){
                throw  new CustomException(AppHttpCodeEnum.WEMEDIA_REFRIENCE_FAIL);
            }

            //仅仅拿到对象数组中的 id的集合
            List<Integer> materialIds  = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
            wmNewsMaterialMapper.saveRelations(materialIds , wmNews.getId() , type);

        }


    }

    /**
     * 保存或者修改文章
     */
    private void saveOrUploadNews(WmNews wmNews){
        //补全wnNews属性
        wmNews.setUserId(WmThreadLocalUtil.get().getId());
        wmNews.setEnable((short)1); //默认是做上架

        //保存或者修改文章
        if (wmNews.getId() == null){
            //第一次创建文章
            save(wmNews);
        }else{
            //修改文章
            //先删除所有  文章和素材的关联关系， 因为关联关系过多无法逐条删除，直接全删
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId ,wmNews.getId()));
            updateById(wmNews);  //?? 修改之后关联关系不重建了吗？
        }
    }


    /**
     * 抽取出文章中的素材列表
     */
    private  List<String> extractMaterials(WmNews wmNews){

        List<String> materials = new ArrayList<>();

        String content = wmNews.getContent();
        List<Map> maps = JSONArray.parseArray(content, Map.class);
        for (Map map : maps) {
            String type = (String) map.get("type");
            if (type.equals("image")){
                materials.add((String) map.get("value"));
            }
        }

        return materials;
    }

}
